package step

import (
	"math/big"

	"github.com/wanchain/go-mpc/log"
	"github.com/wanchain/go-mpc/p2p/discover"
	"github.com/wanchain/go-mpc/storeman/osmconf"
	mpcprotocol "github.com/wanchain/go-mpc/storeman/storemanmpc/protocol"
)

type TXSign_Lagrange_StepUni struct {
	BaseMpcStep
	resultKeys []string
	signNum    int
}

func CreateTXSign_Lagrange_StepUni(totalNum int, preValueKeys []string, resultKeys []string) *TXSign_Lagrange_StepUni {
	log.SyslogInfo("CreateTXSign_Lagrange_Step begin")

	signNum := len(preValueKeys)
	mpc := &TXSign_Lagrange_StepUni{*CreateBaseMpcStep(totalNum, signNum), resultKeys, signNum}

	for i := 0; i < signNum; i++ {
		mpc.messages[i] = createLagrangeGenerator(preValueKeys[i])
	}

	log.SyslogDebug("CreateTXSign_Lagrange_Step succeed")
	return mpc
}

func (lagStep *TXSign_Lagrange_StepUni) GetMsgGens() []MpcMessageGenerator {
	return lagStep.messages
}

func (lagStep *TXSign_Lagrange_StepUni) CreateMessage() []mpcprotocol.StepMessage {
	log.SyslogDebug("TXSign_Lagrange_StepUni.CreateMessage begin")
	_, grpIdstr, _ := osmconf.GetGrpId(lagStep.mpcResult)
	message := make([]mpcprotocol.StepMessage, lagStep.totalNum)

	for i := 0; i < lagStep.totalNum; i++ {
		message[i].MsgCode = mpcprotocol.MPCMessage
		nodeId, _ := osmconf.GetOsmConf().GetNodeIdByIndex(grpIdstr, uint16(i))
		message[i].PeerID = nodeId
	}

	for i := 0; i < lagStep.signNum; i++ {
		lag := lagStep.messages[i].(*lagrangeGenerator)
		for j := 0; j < lagStep.totalNum; j++ {
			message[j].Data = append(message[j].Data, lag.seed)
		}
	}

	log.SyslogDebug("TXSign_Lagrange_StepUni.CreateMessage succeed")
	return message
}

func (lagStep *TXSign_Lagrange_StepUni) HandleMessage(msg *mpcprotocol.StepMessage) bool {
	log.SyslogInfo("..........TXSign_Lagrange_StepUni.HandleMessage begin", "peerID", msg.PeerID.SlimString(), "ctx", lagStep.GetMpcContextId(), "StepId", msg.StepId)

	//seed := lagStep.getPeerSeed(msg.PeerID)
	//if seed == 0 {
	//	log.SyslogErr("TXSign_Lagrange_Step.HandleMessage, get seed fail. peer:%s", msg.PeerID.String())
	//	return false
	//}

	for i := 0; i < lagStep.signNum; i++ {
		lag := lagStep.messages[i].(*lagrangeGenerator)
		_, exist := lag.message[*msg.PeerID]
		if exist {
			log.SyslogErr("TXSign_Lagrange_StepUni.HandleMessage, get msg fail", "peerID", msg.PeerID.SlimString(), "ctx", lagStep.GetMpcContextId())
			return false
		}

		lag.message[*msg.PeerID] = msg.Data[i]
	}

	log.SyslogInfo("TXSign_Lagrange_StepUni.HandleMessage succees")
	return true
}

func (lagStep *TXSign_Lagrange_StepUni) SetSOKIndex() {
	log.SyslogDebug("TXSign_Lagrange_Step SetSOKIndex")

	_, grpIdString, err := osmconf.GetGrpId(lagStep.mpcResult)
	if err != nil {
		return
	}

	okIndex := make([]big.Int, 0)
	idxMap := make(map[discover.NodeID]uint16)

	for i := 0; i < lagStep.signNum; i++ {
		lag := lagStep.messages[i].(*lagrangeGenerator)
		for peerId, _ := range lag.message {
			_, exist := idxMap[peerId]
			if !exist {
				idx, err := osmconf.GetOsmConf().GetInxByNodeId(grpIdString, &peerId)
				if err == nil {
					idxMap[peerId] = idx
				}
			}
		}
	}

	for _, idx := range idxMap {
		okIndex = append(okIndex, *big.NewInt(0).SetInt64(int64(idx)))
	}

	lagStep.mpcResult.SetValue(mpcprotocol.SOKIndex, okIndex)
}

func (lagStep *TXSign_Lagrange_StepUni) FinishStep(result mpcprotocol.MpcResultInterface, mpc mpcprotocol.StoremanManager) error {
	log.SyslogDebug("TXSign_Lagrange_Step.FinishStep begin")

	err := lagStep.BaseMpcStep.FinishStep()
	if err != nil {
		return err
	}

	for i := 0; i < lagStep.signNum; i++ {
		lag := lagStep.messages[i].(*lagrangeGenerator)
		err = result.SetValue(lagStep.resultKeys[i], []big.Int{lag.result})
		if err != nil {
			return err
		}
	}

	log.SyslogDebug("TXSign_Lagrange_Step.FinishStep succeed")
	return nil
}
